package com.prj.ufdm.core.util;

import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.prj.ufdm.core.util.UfdmBase64Util; 

/**
 * 描述：AES 加解密工具类
 * 
 * java的默认jdk 不支持256位AES密钥,需要安装扩展包  http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
 * 下载之后得到 local_policy.jar ，US_export_policy.jar 两个jar包，把这两个jar包放到 jdk/lib/security 目录下，替换原来的两个jar包即可
 * @author 胡义振
 * @date 2018-12-07 
 */
public class UfdmAesUtil {
	
    public static void main(String[] args) throws Exception {
 	   
      String strMing = "浙江网新恩普软件有限公司";
  	  String strKey = "wxepgjjxiajunfng";
  	  String strIvValue = "epsoftfundxiajfg";
  	  String modeAndPadding = "AES/CBC/PKCS5Padding";
  	  int aesType = 128;
  	  String strKeyType = "0";
  	  
        // 加密
        String strMi = encrypt(strMing, strKey, strIvValue, aesType, modeAndPadding, strKeyType, "GBK");
        System.out.println("AES 加密："+ strMi);
        
  	    //strMi = "IbNigEYlNKTn1B2USGyDA9BSqStSPG4dAhfspeXjEs4=";
        String strAesDecrypt =  decrypt(strMi, strKey, strIvValue, aesType, modeAndPadding, strKeyType, "GBK");
        System.out.println("AES 解密："+ strAesDecrypt);

     }

  	/**
  	 * 描述: 通过 AES 进行加密   
  	 * @auther 胡义振
  	 * @date 2018-12-07 
  	 * @param strMing 明文
  	 * @param strKey  密码
  	 * @param strIvValue （只能是16位字符）
  	 * @param aesType
  	 *        128：16 位字符
  	 *        256：32 位字符
  	 * @param encodeType
  	 * @param strKeyType 
  	 *     0: 通过 SecretKeySpec 产生 （AES 加密 "密码"只能支持 16 位字符，24 位字符，32 位字符密码）
  	 *     1: 通过 KeyGenerator  产生 （密码长度为任意长度）
  	 * @return BASE64 密文
  	 * @throws Exception
  	 */
  	public static String encrypt(String strMing,String strKey, String strIvValue, int aesType,String modeAndPadding,String strKeyType,String encoding) throws Exception{
  		
  		SecretKey secretKey = getSecreKey(strKeyType,strKey,aesType);
  		SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
  		if(modeAndPadding==null || "".equals(modeAndPadding)) {
  			modeAndPadding = "AES/CBC/PKCS5Padding";
  		}
  		Cipher cipher = Cipher.getInstance(modeAndPadding);
  		if (null != strIvValue) {
  			cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(strIvValue.getBytes()));
  		} else {
  			cipher.init(Cipher.ENCRYPT_MODE, keySpec);
  		}
  		if(encoding==null || "".equals(encoding)) {
  			encoding = "utf-8";
  		}
  		byte[] encryptByte = cipher.doFinal(strMing.getBytes(encoding));
  		String encryptStr = UfdmBase64Util.encode(encryptByte);
  		return encryptStr;
      }
  	
  	public static String decrypt(String base64Str, String strKey, String strIvValue, int aesType,String modeAndPadding,String strKeyType,String encoding) throws Exception{
  		SecretKey secretKey = getSecreKey(strKeyType,strKey,aesType);
  		SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
  		if(modeAndPadding==null || "".equals(modeAndPadding)) {
  			modeAndPadding = "AES/CBC/PKCS5Padding";
  		}
  		Cipher cipher = Cipher.getInstance(modeAndPadding);
  		if (null != strIvValue) {
  			cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(strIvValue.getBytes()));
  		} else {
  			cipher.init(Cipher.DECRYPT_MODE, keySpec);
  		}
  		byte[] decryptByte = cipher.doFinal(UfdmBase64Util.decode(base64Str));
  		if(encoding==null || "".equals(encoding)) {
  			encoding = "utf-8";
  		}
  		String decryptStr = new String(decryptByte, encoding);
  		return decryptStr;
      }
  		
  	/**
  	 * 描述: 通过密码类型,与密码获取 SecretKey 对象 
  	 * @auther 胡义振
  	 * @date 2018-12-07 
  	 * @param strKeyType 秘钥类型
  	 *     0: 通过 SecretKeySpec 产生 （AES 加密 "秘钥"只能支持 16 位，24 位，32 位密码）
  	 *     1: 通过 KeyGenerator  产生 
  	 * @param strKey 秘钥 
  	 * @param AESType 加密位数
  	 * @return
  	 */
  	private static SecretKey getSecreKey(String strKeyType,String strKey,int aesType){
  		SecretKey secretKey = null;
  		try
  		{
  			// 为了能支持 PKCS7Padding 
  			Security.addProvider(new BouncyCastleProvider());
  			if(strKeyType==null ||  "".equals(strKeyType)) {
  				strKeyType = "0";
  			}
  			// 通过 SecretKeySpec 产生秘钥
  			if("0".equals(strKeyType)){
  				secretKey = new SecretKeySpec(strKey.getBytes(), "AES");
  				
  				System.out.println("密钥的长度为：" + secretKey.getEncoded().length);
  			}
  			// 通过 keyGenerator 产生秘钥
  			else if("1".equals(strKeyType)){
  				if(aesType!=128 && aesType!=256) {
  					aesType = 128;
  				}
  				KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
  				SecureRandom secureRandom = null;
  				if(aesType==128) {
  					secureRandom = SecureRandom.getInstance("SHA1PRNG");
  					secureRandom.setSeed(strKey.getBytes());
  				}
  				else if(aesType==256) {
  	                MessageDigest digester=MessageDigest.getInstance("SHA-256");  
  	                digester.update(strKey.getBytes());  
  	                byte[] arrByteKey = digester.digest();
  	                secureRandom = new SecureRandom(arrByteKey);
  				}
  				keyGenerator.init(aesType,secureRandom);
  				secretKey = keyGenerator.generateKey();
  			}
  		}
  		catch(Exception er){
  			er.printStackTrace();
  		}
  		return secretKey;
  	}
}
